/*
 *   Copyright 2012-present OSBI Ltd
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

// Packages
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { isEmpty } from 'lodash';
import { Button, Icon, Intent, Position, Tooltip } from '@blueprintjs/core';
import { Input, Table } from 'antd';
import Highlighter from 'react-highlight-words';

// Services
import { ConnectionService } from '../../../../../services';

// Actions
import { actionCreators } from '../../../../../actions';

// UI
import { BlockUi, ErrorMessage, Loading, WarningAlert } from '../../../../UI';

// Dialogs
import DataSourceFormDialog from './DataSourceFormDialog';

// Utils
import { Saiku, Settings } from '../../../../../utils';

// Components
const { Column } = Table;

// Constants
const { SAIKU_COLOR } = Settings;
const ERROR_MSG = 'Error fetching data from connections';

class PanelDataSourcesManagement extends Component {
  _isMounted = false;

  state = {
    connections: [],
    selectedDataSourceData: {},
    dataSource: [],
    searchText: '',
    itemToDelete: {},
    isEditModeFormDialog: false,
    isOpenDataSourceFormDialog: false,
    isOpenDeleteAlert: false,
    loading: true,
    error: false,
    errorMsg: ERROR_MSG
  };

  componentDidMount() {
    this._isMounted = true;
    this.callApiGetDataSources();
  }

  componentWillUnmount() {
    this._isMounted = false;
    ConnectionService.cancelRequest();
  }

  callApiGetDataSources = () => {
    this.setState({
      loading: true,
      error: false
    });

    ConnectionService.getDataSources()
      .then(res => {
        if (this._isMounted && res.status === 200) {
          const { data } = res;

          this.setState({
            connections: data,
            dataSource: data.map((conn, index) => {
              return {
                key: conn.id,
                name: conn.connectionname
              };
            }),
            loading: false
          });
        } else {
          if (this._isMounted) {
            this.setState({
              loading: false,
              error: true
            });
          }
        }
      })
      .catch(error => {
        if (this._isMounted) {
          this.setState({
            loading: false,
            error: true
          });
        }
      });
  };

  getTooltipPosition(data) {
    const { searchText } = this.state;

    return data.length === 1 || !isEmpty(searchText)
      ? Position.LEFT_TOP
      : Position.TOP;
  }

  handleRefreshDataSource(dataSourceName) {
    const { requestStart, requestSuccess, requestFailure } = this.props;

    requestStart(
      <BlockUi message={`Refreshing ${dataSourceName} data source...`} />
    );

    ConnectionService.refreshDataSource(dataSourceName)
      .then(res => {
        const { data } = res;

        if (res.status === 200) {
          requestSuccess();

          Saiku.toasts(Position.TOP_RIGHT).show({
            icon: 'tick',
            intent: Intent.SUCCESS,
            message: 'Refreshed!'
          });
        } else {
          requestFailure();
          Saiku.toasts(Position.TOP_RIGHT).show({
            icon: 'error',
            intent: Intent.DANGER,
            message: data
          });
        }
      })
      .catch(error => {
        requestFailure();
        Saiku.toasts(Position.TOP_RIGHT).show({
          icon: 'error',
          intent: Intent.DANGER,
          message: 'Something went wrong'
        });
      });
  }

  getDataSource(id) {
    return this.state.connections.find(conn => conn.id === id);
  }

  handleEditDataSource(id) {
    const selectedDataSourceData = this.getDataSource(id);
    this.handleDataSourceFormDialog(true, selectedDataSourceData);
  }

  handleDeleteDataSource(dataSource) {
    const { requestStart, requestSuccess, requestFailure } = this.props;
    const { id, name } = dataSource;

    requestStart(<BlockUi message={`Deleting ${name} data source...`} />);

    ConnectionService.deleteDataSource(id)
      .then(res => {
        if (res.status === 200) {
          requestSuccess();

          Saiku.toasts(Position.TOP_RIGHT).show({
            icon: 'tick',
            intent: Intent.SUCCESS,
            message: 'Data source deleted'
          });

          this.callApiGetDataSources();
        } else {
          requestFailure();
          Saiku.toasts(Position.TOP_RIGHT).show({
            icon: 'error',
            intent: Intent.DANGER,
            message: 'Something went wrong'
          });
        }
      })
      .catch(error => {
        requestFailure();
        Saiku.toasts(Position.TOP_RIGHT).show({
          icon: 'error',
          intent: Intent.DANGER,
          message: 'Something went wrong'
        });
      });
  }

  getColumnSearchProps = dataIndex => ({
    filterDropdown: ({
      setSelectedKeys,
      selectedKeys,
      confirm,
      clearFilters
    }) => (
      <div style={{ padding: 8 }}>
        <Input
          ref={node => (this.searchInput = node)}
          placeholder={`Search ${dataIndex}`}
          value={selectedKeys[0]}
          onChange={e =>
            setSelectedKeys(e.target.value ? [e.target.value] : [])
          }
          onPressEnter={() => this.handleSearch(selectedKeys, confirm)}
          style={{ width: 188, marginBottom: 8, display: 'block' }}
        />
        <Button
          icon="search"
          text="Search"
          intent={Intent.DANGER}
          style={{ width: 90, marginRight: 8 }}
          onClick={() => this.handleSearch(selectedKeys, confirm)}
          small
        />
        <Button
          text="Reset"
          style={{ width: 90 }}
          onClick={() => this.handleReset(clearFilters)}
          small
        />
      </div>
    ),

    filterIcon: filtered => (
      <Icon
        icon="search"
        iconSize={12}
        style={{ color: filtered ? SAIKU_COLOR : undefined }}
      />
    ),

    onFilter: (value, record) => {
      return record[dataIndex]
        .toString()
        .toLowerCase()
        .includes(value.toLowerCase());
    },

    onFilterDropdownVisibleChange: visible => {
      if (visible) {
        setTimeout(() => this.searchInput.select());
      }
    },

    render: text => (
      <Highlighter
        highlightStyle={{ backgroundColor: '#ffc069', padding: 0 }}
        searchWords={[this.state.searchText]}
        autoEscape
        textToHighlight={text && text.toString() ? text.toString() : ''}
      />
    )
  });

  handleSearch = (selectedKeys, confirm) => {
    confirm();
    this.setState({ searchText: selectedKeys[0] });
  };

  handleReset = clearFilters => {
    clearFilters();
    this.setState({ searchText: '' });
  };

  handleDataSourceFormDialog = (isEditMode = false, selectedDataSourceData) => {
    this.setState(prevState => ({
      selectedDataSourceData,
      isEditModeFormDialog: isEditMode,
      isOpenDataSourceFormDialog: !prevState.isOpenDataSourceFormDialog
    }));
  };

  handleDeleteAlert = dataSource => {
    this.setState(
      prevState => ({
        isOpenDeleteAlert: !prevState.isOpenDeleteAlert
      }),
      () => {
        if (dataSource) {
          this.setState({
            itemToDelete: { id: dataSource.key, name: dataSource.name }
          });
        }
      }
    );
  };

  renderTable() {
    const {
      selectedDataSourceData,
      dataSource,
      itemToDelete,
      isEditModeFormDialog,
      isOpenDataSourceFormDialog,
      isOpenDeleteAlert
    } = this.state;

    return (
      <Fragment>
        <div className="sku-btn-group-end m-b-10">
          <Button
            icon="plus"
            text="Add Data Source"
            intent={Intent.DANGER}
            onClick={this.handleDataSourceFormDialog.bind(this, false)}
            small
          />
        </div>
        <Table
          dataSource={dataSource}
          pagination={{ pageSize: 10 }}
          scroll={{ y: 240 }}
          size="middle"
        >
          <Column
            title="Data Sources"
            dataIndex="name"
            key="name"
            width="30%"
            {...this.getColumnSearchProps('name')}
          />
          <Column
            align="right"
            title="Action"
            key="action"
            render={(text, record) => (
              <span>
                <Tooltip
                  content={<span>Refresh Cache</span>}
                  position={this.getTooltipPosition(dataSource)}
                >
                  <Button
                    icon="refresh"
                    intent={Intent.PRIMARY}
                    onClick={this.handleRefreshDataSource.bind(
                      this,
                      record.name
                    )}
                    minimal
                  />
                </Tooltip>
                <Tooltip
                  content={<span>Edit</span>}
                  position={this.getTooltipPosition(dataSource)}
                >
                  <Button
                    icon="edit"
                    intent={Intent.PRIMARY}
                    onClick={this.handleEditDataSource.bind(this, record.key)}
                    minimal
                  />
                </Tooltip>
                <Tooltip
                  content={<span>Delete</span>}
                  position={this.getTooltipPosition(dataSource)}
                >
                  <Button
                    icon="trash"
                    intent={Intent.DANGER}
                    onClick={this.handleDeleteAlert.bind(this, record)}
                    minimal
                  />
                </Tooltip>
              </span>
            )}
          />
        </Table>

        {isOpenDataSourceFormDialog && (
          <DataSourceFormDialog
            editMode={isEditModeFormDialog}
            dataSourceData={selectedDataSourceData}
            getDataSources={this.callApiGetDataSources}
            onClose={this.handleDataSourceFormDialog.bind(this, false)}
          />
        )}

        {isOpenDeleteAlert && (
          <WarningAlert
            confirmButtonText="Delete"
            icon="trash"
            message={
              <span>
                Are you sure you want to delete the <b>{itemToDelete.name}</b>{' '}
                data source?
              </span>
            }
            onCancel={this.handleDeleteAlert}
            onConfirm={this.handleDeleteDataSource.bind(this, itemToDelete)}
          />
        )}
      </Fragment>
    );
  }

  render() {
    const { loading, error, errorMsg } = this.state;

    return loading ? (
      <Loading className="m-t-10 m-b-10" size={30} center />
    ) : error ? (
      <ErrorMessage text={errorMsg} callApi={this.callApiGetDataSources} />
    ) : (
      this.renderTable()
    );
  }
}

PanelDataSourcesManagement.propTypes = {
  requestStart: PropTypes.func.isRequired,
  requestSuccess: PropTypes.func.isRequired,
  requestFailure: PropTypes.func.isRequired
};

const mapDispatchToProps = dispatch => ({
  requestStart: message => dispatch(actionCreators.requestStart(message)),
  requestSuccess: () => dispatch(actionCreators.requestSuccess()),
  requestFailure: () => dispatch(actionCreators.requestFailure())
});

export default connect(
  null,
  mapDispatchToProps
)(PanelDataSourcesManagement);
